/*
 *  Copyright (C) 2010 Matthias Buch-Kromann <mbk.isv@cbs.dk>
 * 
 *  This file is part of the IncrementalParser package.
 *  
 *  The IncrementalParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.osdtsystem.incparser.logging;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

/**
 *
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
public class Log {
    // Set to "null" and call update() to turn off debugging
    static String parserLogDir = null;

    static List<Long> startTimes = new ArrayList<Long>();

    public static long lastStartTime() {
        return startTimes.size() > 0
                ? startTimes.get(startTimes.size() - 1)
                : System.currentTimeMillis();
    }

    public static void pushStartTime() {
        startTimes.add(System.currentTimeMillis());
    }

    public static void popStartTime() {
        startTimes.remove(startTimes.size() - 1);
    }

    public static long secondsElapsed() {
        return (System.currentTimeMillis() - lastStartTime()) / 1000;
    }

    public static long memoryUsed() {
        return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
                / (1024 * 1024);
    }

    public static SimpleFormatter formatter = new SimpleFormatter() {
            @Override
            public synchronized String format(LogRecord record) {
                return record.getMessage();
            }
        };

    public static ParserHandler phandler
            = createParserHandler();
    public static ConsoleHandler chandler
            = createConsoleHandler();
    public static Logger logger = createLogger();

    public static void setParserLogDir(String directory) {
        parserLogDir = directory != null ? directory + "/" : null;
        phandler = null;
        logger = null;
        phandler = createParserHandler();
        logger = createLogger();
    }
    
    public static Logger createLogger() {
        if (logger != null)
            return logger;
        
        // Create logger
        Logger newlogger = Logger.getLogger("IncrementalParser");
        newlogger.setUseParentHandlers(false);
        for (Handler h : newlogger.getHandlers())
            newlogger.removeHandler(h);

        // Create new handler
        Handler handler = createConsoleHandler();
        handler.setFormatter(formatter);
        newlogger.addHandler(handler);
        newlogger.addHandler(createParserHandler());
        setLevel(newlogger, Level.ALL);
        handler.setLevel(Level.CONFIG);
        
        // Return logger
        return(newlogger);
    }

    public static ConsoleHandler createConsoleHandler() {
        if (chandler != null)
            return(chandler);
        return(chandler = new ConsoleHandler());
    }

    public static ParserHandler createParserHandler() {
        if (phandler != null)
            return(phandler);
        
        try {
            if (parserLogDir == null) {
                phandler = new ParserHandler();
                return(phandler);
            } else {
                phandler = new HtmlDirectoryParserHandler(formatter, parserLogDir);
                return(phandler);
            }
        } catch (IOException ex) {
            Logger.getLogger(Log.class.getName()).log(Level.SEVERE, null, ex);
            return(new ParserHandler());
        } catch (SecurityException ex) {
            Logger.getLogger(Log.class.getName()).log(Level.SEVERE, null, ex);
            return(new ParserHandler());
        }
    }

    public static void setLevel(Level newLevel) {
        setLevel(logger, newLevel);
    }
    
    public static void setLevel(Logger logger, Level newLevel) {
        logger.setLevel(newLevel);
        for (Handler handler : logger.getHandlers())
            handler.setLevel(newLevel);
    }

    public static void log(Level level, boolean newLine, Object[] objects) {
        if (logger.getLevel().intValue() <= level.intValue()) {
            StringBuilder s = new StringBuilder();
            for (Object object : objects)
                s.append(object.toString());
            if (newLine)
                s.append("\n");
            logger.log(level, s.toString());
        }
    }

    public static void log(Level level, Object[] objects) {
        log(level, true, objects);
    }

    public static void logW(Level level, Object[] objects) {
        log(level, false, objects);
    }

    public static void severe(Object... objects) {
        log(Level.SEVERE, objects);
    }

    public static void warning(Object... objects) {
        log(Level.SEVERE, objects);
    }

    public static void info(Object... objects) {
        log(Level.INFO, objects);
    }

    public static void config(Object... objects) {
        log(Level.CONFIG, objects);
    }

    public static void fine(Object... objects) {
        log(Level.FINE, objects);
    }

    public static void finer(Object... objects) {
        log(Level.FINER, objects);
    }

    public static void finest(Object... objects) {
        log(Level.FINEST, objects);
    }

    public static void severeW(Object... objects) {
        logW(Level.SEVERE, objects);
    }

    public static void warningW(Object... objects) {
        logW(Level.SEVERE, objects);
    }

    public static void infoW(Object... objects) {
        logW(Level.INFO, objects);
    }

    public static void configW(Object... objects) {
        logW(Level.CONFIG, objects);
    }

    public static void fineW(Object... objects) {
        logW(Level.FINE, objects);
    }

    public static void finerW(Object... objects) {
        logW(Level.FINER, objects);
    }

    public static void finestW(Object... objects) {
        logW(Level.FINEST, objects);
    }

    public static boolean isLogged(Level level) {
        return logger.getLevel().intValue() < level.intValue();
    }
}
